package ru.nsu.ccfit.kalah.view.field;

import android.content.Context;
import android.graphics.*;
import android.media.MediaPlayer;
import android.util.AttributeSet;

import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;
import android.widget.FrameLayout;
import android.widget.Toast;
import ru.nsu.ccfit.kalah.R;
import ru.nsu.ccfit.kalah.game.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Vector;

public class FieldView extends View implements MoveAnimatorListener {
    private Field field;
    int width;
    int height;
    private SelectListener selectListener;


    private List<Ball> balls[] = new ArrayList[14];
    private int radius = 20;
    private int DELAY = 550; //550


    MoveAnimator animator = new MoveAnimator() {
        @Override
        public void move(final int from, final int to) {
            int count = field.get(from);
            field.set(from, count - 1);

            int toCount = field.get(to);
            field.set(to, toCount + 1);

            final Ball ball = balls[from].remove(balls[from].size() - 1);
            balls[to].add(ball);

            List<Ball> ballList = new ArrayList<Ball>();
            List<PointF> beginPointsList = new ArrayList<PointF>();
            List<PointF> endPointsList = new ArrayList<PointF>();
            ballList.add(ball);
            beginPointsList.add(ball.getPosition());
            endPointsList.add(generateRandomPosition(rects.get(to), radius));
            BallAnimation animation = new BallAnimation(ballList, beginPointsList, endPointsList);
            animation.setAnimationListener(animationListener);
            animation.setInterpolator(new AccelerateDecelerateInterpolator());
            animation.setDuration(DELAY / 2);
            startAnimation(animation);

            invalidate();
        }

        @Override
        public void moveAll(int fromFirst, int fromSecond, int to) {
            int count = field.get(fromFirst);
            field.set(fromFirst, 0);
            int toCount = field.get(to);
            field.set(to, toCount + count);

            List<Ball> ballList = new ArrayList<Ball>();
            List<PointF> beginPointsList = new ArrayList<PointF>();
            List<PointF> endPointsList = new ArrayList<PointF>();
            for (int i = 0; i < count; i++) {
                final Ball ball = balls[fromFirst].remove(balls[fromFirst].size() - 1);
                balls[to].add(ball);


                ballList.add(ball);
                beginPointsList.add(ball.getPosition());
                endPointsList.add(generateRandomPosition(rects.get(to), radius));


            }

            count = field.get(fromSecond);
            field.set(fromSecond, 0);
            toCount = field.get(to);
            field.set(to, toCount + count);

            for (int i = 0; i < count; i++) {
                final Ball ball = balls[fromSecond].remove(balls[fromSecond].size() - 1);
                balls[to].add(ball);


                ballList.add(ball);
                beginPointsList.add(ball.getPosition());
                endPointsList.add(generateRandomPosition(rects.get(to), radius));


            }

            BallAnimation animation = new BallAnimation(ballList, beginPointsList, endPointsList);
            animation.setAnimationListener(animationListener);
            animation.setInterpolator(new AccelerateDecelerateInterpolator());
            animation.setDuration(DELAY);
            startAnimation(animation);


            invalidate();
        }
    };

    Animation.AnimationListener animationListener = new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
            //To change body of implemented methods use File | Settings | File Templates.
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            MediaPlayer mp = MediaPlayer.create(getContext(), R.raw.sound);
            mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

                @Override
                public void onCompletion(MediaPlayer mp) {

                    mp.release();
                }

            });
            mp.start();
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
            //To change body of implemented methods use File | Settings | File Templates.
        }
    };

    class AnimateRunnable implements Runnable {
        AbstractMoveAnimation animation;

        AnimateRunnable(AbstractMoveAnimation animation) {
            this.animation = animation;
        }

        @Override
        public void run() {
            animation.animate(animator);
        }
    }


    @Override
    public void animate(final List<AbstractMoveAnimation> abstractMoves, final RequestMoveCallback callback) {


        long delay = 0;
        for (AbstractMoveAnimation animation : abstractMoves) {
            delay += DELAY * 1.2;
            postDelayed(new AnimateRunnable(animation), delay);
        }
        postDelayed(new Runnable() {
            @Override
            public void run() {
                callback.request();
            }
        }, delay + DELAY);
    }

    public void setSelectListener(SelectListener selectListener) {
        this.selectListener = selectListener;
    }

    public FieldView(Context context) {
        super(context);

        init();

    }


    public FieldView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public FieldView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        field = new Field();


    }

    public void setField(Field field) {
        this.field = field;
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        pitSize = w / 8;
        initRects();


        invalidate();
    }

    /*  @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   super.onMeasure(widthMeasureSpec, heightMeasureSpec);
   int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
   int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
   setMeasuredDimension(parentWidth, pitSize*2+SCORE_HEIGHT*2);
}
    */
    int pitSize = 50;
    int SCORE_HEIGHT = 60;
    private List<RectF> rects = new ArrayList<RectF>();
    private List<RectF> scoreRects = new ArrayList<RectF>();

    private PointF generateRandomPosition(RectF rect, int radius) {
        PointF point = new PointF();
        Random random = new Random();
        rect.sort();
        int border = 5;
        point.set(rect.left + border + radius + random.nextInt((int) (rect.width() - 2 * radius - 2 * border)), rect.top + radius + border + random.nextInt((int) (rect.height() - 2 * radius - 2 * border)));


        return point;
    }

    private int generateRandomColor() {
        int[] colors = {Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW, Color.MAGENTA, Color.CYAN};
        return colors[new Random().nextInt(colors.length)];
    }

    private void initRects() {

        for (int i = 0; i < balls.length; i++) {
            balls[i] = new ArrayList<Ball>();
        }

        int offset = getHeight() / 2 - pitSize;

        RectF scoreHouseRect = new RectF(0, 2 * pitSize, pitSize, 2 * pitSize + SCORE_HEIGHT);

        RectF houseRect = new RectF(0, 0, pitSize, 2 * pitSize);
        houseRect.offset(0, offset);
        scoreHouseRect.offset(0, offset);
        // 0
        rects.add(new RectF(houseRect));
        scoreRects.add(new RectF(scoreHouseRect));

        RectF rect = new RectF(pitSize, pitSize, 2 * pitSize, 2 * pitSize);
        RectF scoreRect = new RectF(pitSize, 2 * pitSize, 2 * pitSize, 2 * pitSize + SCORE_HEIGHT);
        rect.offset(0, offset);
        scoreRect.offset(0, offset);
        // 1 2 3 4 5 6
        for (int i = 0; i < 6; i++) {
            rects.add(new RectF(rect));

            scoreRects.add(new RectF(scoreRect));

            for (int j = 0; j < 6; j++) {
                balls[i + 1].add(new Ball(generateRandomPosition(rect, radius), radius, generateRandomColor()));
            }

            rect.offset(pitSize, 0);
            scoreRect.offset(pitSize, 0);
        }
        // 7
        houseRect.offset(7 * pitSize, 0);
        scoreHouseRect.offset(7 * pitSize, 0);
        rects.add(new RectF(houseRect));
        scoreRects.add(new RectF(scoreHouseRect));
        //  8 9 10 11 12 13
        rect.offset(-pitSize, -pitSize);
        scoreRect.offset(-pitSize, -pitSize * 2 - SCORE_HEIGHT);
        for (int i = 0; i < 6; i++) {
            rects.add(new RectF(rect));
            scoreRects.add(new RectF(scoreRect));
            for (int j = 0; j < 6; j++) {
                balls[i + 8].add(new Ball(generateRandomPosition(rect, radius), radius, generateRandomColor()));
            }
            rect.offset(-pitSize, 0);
            scoreRect.offset(-pitSize, 0);
        }
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            for (int i = 0; i < rects.size(); i++) {
                RectF rect = rects.get(i);
                //     int offset = -(getHeight()/2 + pitSize);
                if (rect.contains(event.getX(), event.getY())) {
                    if (selectListener != null) {
                        selectListener.onSelected(i);
                    }
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //     canvas.translate(0, getHeight()/2 - pitSize);
        canvas.drawColor(Color.WHITE);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.STROKE);

        Paint textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setColor(Color.BLACK);
        textPaint.setTextAlign(Paint.Align.CENTER);
        textPaint.setTextSize(50);
        float fontHeight = Math.abs(textPaint.ascent() + textPaint.descent()) / 2.0f;
        for (int i = 0; i < rects.size(); i++) {
            RectF rect = rects.get(i);
            canvas.drawRect(rect, paint);


        }
        for (int i = 0; i < rects.size(); i++) {
            RectF rect = scoreRects.get(i);
            canvas.drawText(Integer.toString(field.get(i)), rect.centerX(), rect.centerY() + fontHeight, textPaint);


        }


        for (List<Ball> ballList : balls) {
            for (Ball ball : ballList) {
                ball.draw(canvas);
            }
        }


    }


}
